51. Tradition for C++ new & delete

operator new
할당된 메모리의 첫 주소를 반환하며, 가용 메모리가 부족할 경우 new-handler를 호출한다.
크기가 없는 메모리(0바이트) 요청에 대한 대비책을 갖추어야 한다.
기본의 new-handler 함수를 가리지 않도록 보장해야 한다.
(메모리를 반환할 수 없는 경우, bad_alloc 타입의 예외를 던짐)

operator new는 메모리 할당을 실패할 때마다 new-handler 함수를 호출해서 메모리 할당을 2회 이상
시도한다. new-handler 함수에 대한 포인터가 null인 경우만 예외를 던진다.
void* operator new(std::size_t size) throw(std::bad_alloc){
using namespace std;
if(size==0){ // 0 , 1
size=1;
}
while(true){
//size
if(/* */) return //
// , new-handler
// new-handler
new_handler globalHandler=set_new_handler(0);
set_new_handler(globalHandler);
if(globalHandler)(*globalHandler)();
else throw std::bad_alloc();
}
} //
operator new 함수는 무한 루프를 포함한다. while(true)
루프를 빠져나오기 위해서는 메모리 할당이 성공하던지, new-handler 함수에서 처리해 주어야 한다.

operator new 멤버 함수는 클래스를 상속할 때, 파생클래스로 상속이 되는 함수이다.
class Base{
public:
static void* operator new(std::size_t size) throw(std::bad_alloc);
// ...
};
class Derived: public Base{
// ...
};
Derived* p=new Derived; // Base::operator new
의도치 않게 파생 클래스에서 기본 클래스의 operator new를 사용할 수 있다.
operator new가 잘못된 크기의 메모리 크기가 들어왔을 때, 처리할 수 있도록 구현해야 한다.
void* Base::operator new(std::size_t size) throw(bad_alloc){
if(size!=sizeof(Base))
return ::operator new(size); // operator new
// ...
}
객체는 항상 크기가 0을 넘기 때문에 Base의 사이즈가 0이 됨은 검사하지 않아도 됨

배열에 대한 메모리 할당을 처리하고 싶은 경우, operator new[]함수를 구현
operator delete
C++는 널 포인터에 대한 delete 적용이 항상 안정하도록 보장해야 한다.
void operator delete(void* rawMemory) throw(){
if(rawMemory==0) return; // nullptr ,
// rawMemory
}
단, 삭제할 메모리의 크기를 점검하는 코드가 필요하다.
operator new가 틀린 크기의 메모리 요청을 ::operator new쪽으로 넘기도록 구현되어 있다면,
operator delete 역시 틀린 크기의 메모리의 삭제 요청을 ::operator delete로 전달해야 한다.
class Base{
public:
static void* operator new(std::size_t size) throw(std::bad_alloc);
static void operator delete(void* rawMemory, std::size_t size) throw();
// ...
};
void Base::operator delete(void* rawMemory, std::size_t size) throw(){
if(rawMemory==0) return;
if(size!=sizeof(Base)){
::operator delete(rawMemory);
return;
}
// rawMemory
return;
}
기본 클래스의 소멸자가 가상(virtual)로 선언되어 있지 않은 경우,
operator delete로 전달되는 size_t값이 엉터리일 수 있다.
기본 클래스의 소멸자는 가상으로 선언할 것